iT邦幫忙

2026 iThome 鐵人賽

DAY 11
0
AI Engineering

從單一agent 到多agent 集群的開發流水帳以及應用系列 第 14

Day 11:從來沒紅過的燈,不是綠燈

  • 分享至 

  • xImage
  •  

系列:「從單一 agent 到多 agent 集群,再到接進我的生活」;不設天數,第 11 篇

前言

Day 10 收工時最誠實的一句話是:現在沒有綠燈紀錄。
而 Day 10 學到的第一件事是:綠燈不是證據。

那就把這兩句放在一起。這個專案信賴的燈不只一盞——本機全量、app 的 vitest、
GitHub 上的六七個 workflow、Day 10 自己加的兩道閘、幾條 ratchet。每一盞都在說
「綠」或「紅」,而我從來沒有把它們排成一列,逐盞問同一個問題:

你紅過嗎?

今天不修某個功能,做的是 Day 7 以來同一件事,只是對象換成燈本身:去量一件從來
沒有被量過的東西,然後修掉量出來的結果。

架構圖

Day 11 九盞燈盤點:真綠一盞、紅得對三盞(都沒人看)、從沒亮過四盞、待量一盞

先數,再修

早上先讓 22 個 agent 對整個 repo 做一輪唯讀的對抗式調查(7 個調查員、每條主張一個
駁斥者、一個「你們漏了什麼」的批評者),不准跑 cargo。目的不是修,是拿到清單
早上的清單有五盞;另外四盞是白天一路撞到的。全部排在一起:

# 它說 實情 什麼時候撞到
1 app vitest 上次 655 passed 08-28 之後沒整套量過 早上
2 本機 Rust 全量 「三千六百條全綠」 09-01 之後沒綠過;之後兩次都在 1849/3591 停;1742 條從沒跑過 早上
3 paired_gate_check.sh Day 10 加的閘 對 259 個 commit 判 ✅,證據是一段 prose 早上
4 cargo-audit-nightly 每晚守著 從 05-17 起 110/110 紅 早上
5 Security Scan 08-24 起紅在一條真 advisory,沒人讀 早上
6 gitleaks PR 上的秘密掃描 最近 40/40 紅,從沒掃過一個 PR 開 PR 時
7 Dependency Review PR 上的依賴審查 最近 40/40 紅,在這裡跑不起來 開 PR 時
8 main 的 clippy main 從 08-12 就紅;stable 走到 1.98 又疊一層,沒人看見 開 PR 時
9 Linux service install 綠(Mac 上看不到) 改名那天起壞,蓋在 clippy 下面 剝開 clippy 之後

還有一件不算燈、但決定所有燈有沒有人看的事:dev 分支上零次 workflow 觸發
每一個 workflow 都只看 main,而 main 08-12 之後沒有任何 push 或 PR。這條分支上 57 個
commit,GitHub 一次都沒看過。

九盞。文章寫到這裡的時候,我還不知道幾盞是真的。下面按實際動手的順序。

第一盞:app 的 vitest —— 十九秒,真綠

這是清單裡唯一不搶 build lock 的燈,所以第一個跑:

Test Files  118 passed (118)
     Tests  653 passed | 8 skipped (661)
Duration    19s

真綠。上一次有紀錄是 08-28 的 655 passed;中間 13 個 commit 動過 app/,沒有任何
workflow 跑它——不是它壞了,是沒有人看。一盞燈綠了一週沒人看,跟紅了一週沒人看,
對專案的意義是一樣的:零。

第二盞:本機全量 —— 我在 Day 10 又寫錯一句

Day 10 寫:

apex4_phone_roundtrip.rs:77test_rpc_forwarding.rs:103 本來就會用簽章正確的
遠端請求打 SELF_GATED_ROUTES 裡的路由——那些測試會紅。

早上的調查員去讀了程式,駁斥者再去讀一次,結論一致:那兩條不紅。 它們用的
auth_gate::signed_request 會替請求塞進 ConnectInfo,middleware 對 SELF_GATED_ROUTES
會站開,handler 只驗一次章。

真正紅的是另外兩條,而且是上一輪全量已經跑出來、我沒看的:

FAIL serve::api_events_route_tests::capability_query_route_is_wired_and_auth_gated
     unauthenticated POST /rpc/capability-query must be rejected (401/403), got 500
FAIL serve::api_events_route_tests::onboarding_non_table_key_returns_graceful_500_not_panic
     Missing request extension: ConnectInfo<SocketAddr> was not found

根因跟簽章無關:gate_api_and_rpc(serve.rs:267-272)的簽名要求一個
ConnectInfo<SocketAddr> extractor,而 axum 0.7.9 的 from_fn沒有帶這個 extension
的請求
,在進 middleware 本體之前就回 500。用 Request::builder() 直接打 router 的
測試沒有 peer address,就是這種請求。

第一條測試把那個 500 讀成「被拒絕」。它沒有。500 不是拒絕,也不是放行,它是壞掉。
assert_ne!(status, 401) 這種形狀的斷言,對 500 是綠的。

批評者的靜態掃描估同一家族約 27 條(lib 13 + test_security_t7 4 + t7b 9),
其中一條「拿到 500 也算綠」。這數字是估的,下面用跑的。

修之前,先量一次

Day 7 的規矩:先量再修。所以第一件事不是改 middleware,是把全量在改動之前跑一遍,
--no-fail-fast,讓 1742 條從沒跑過的測試一次全部報到:

START 18:17:42  HEAD=b7377c13  core_clean=0
Finished `test` profile in 18m 35s
Starting 3591 tests across 201 binaries (70 tests skipped)
Summary [ 176.001s ] 3591 tests run: 3546 passed, 45 failed, 70 skipped
EXIT=100
END   20:02:26

整輪 1 小時 45 分:編譯 18 分半、測試 3 分鐘、中間 81 分鐘在 macOS Gatekeeper——
nextest 對 201 個剛 link 出來的 binary 逐支 --list,每支停在 S 狀態等 syspolicyd
審核,約 25 秒一支,序列不平行。這件事本身也是一盞燈:Day 8 量過一次「45 分鐘」,
今天 201 支是 81 分鐘;它跟程式碼無關,跟 binary 數量成正比,而且 lib 一改就全部重付。

45 條紅。按 binary 分:

binary 原因
lib serve::* 15 ConnectInfo 500
skill_rpc_skills 14 3 條 ConnectInfo 500;11 條是另一件事(下面說)
test_security_t7b 8 ConnectInfo 500
test_security_t7 4 ConnectInfo 500
test_rpc_forwarding 1 真 TCP 沒帶 connect info → 拿到 500 的純文字 body,「error decoding response body」
p9_the_shell_cannot_pin_itself 1 跟 auth 無關:/sw.js 又把 HTML shell 放進 precache——Day 9 的 p9 測試,今天沒動
the_app_only_calls_routes_that_exist 1 掃描器看不到 "{}/…" literal,checked=0,撞自己的下限
skill_rpc_skillssearch_fts5_p99_latency 1 時間斷言,兩次嘗試都超過 200 ms——跟 main 第四層同一條測試,這次量到的是 syspolicyd 佔著 40% CPU 的這台 Mac

31 條同一個根因(ConnectInfo)。早上靜態估 27,實跑 31——差在哪?middleware 包的是
整個 router,extractor 在進函式之前就跑,所以連沒有閘的路徑也被 500 掉。靜態掃描只數了
「打閘的測試」,少算了「打任何路徑但沒帶地址的測試」。這也是今天的規矩:估的寫「估」,
跑完再寫數字。

然後是 skill_rpc_skills 那 11 條。它們有簽章——用的就是 auth_gate::signed_request,
帶 ConnectInfo、帶正確的 HMAC——卻被拒:

{"error":"unauthorized — bad or missing X-Cluster-Auth / X-Cluster-Timestamp / X-Cluster-Nonce"}

一個簽對的請求被說「簽章壞了」。這個形狀我在 Day 9 見過:middleware 驗一次、燒掉 nonce,
handler 自己再驗一次,第二次看到的就是重放。Day 9 為此建了 SELF_GATED_ROUTES——35 條
「handler 自己驗章、middleware 站開」的路由,而那份清單是serve.rs 反推出來的
/api/skills* 這組路由是 feature-gated、掛在另一個檔案,不在 serve.rs 裡,清單沒看到它。
「清點器只清點它名字裡那片」——如果證實,這是第六次。今晚沒證實:形狀一模一樣,但我沒有
去讀那個 handler,所以這裡寫「疑似」,明天先紅證再修。

我一開始把這 11 條也算進 ConnectInfo 家族,寫成「43 條同一根因」。看到 panic 訊息才
發現不是——同一個 binary 裡兩種紅,要一條一條讀訊息才分得開。按 binary 數是清點,
按訊息分才是量測。

第 44 條(route ratchet 的下限斷言)早上的批評者就預測到了:那條掃描器跳過所有
"{}/..." 開頭的字面值,所以它看到 0 條 app 端路徑,先撞自己的 floor:

一條跟 hub_url 同行的字面路徑都沒有 —— 這條掃描已經對不上程式碼的形狀了

它紅得對——一個掃描器要先證明自己看得到東西,而它誠實地說了自己看不到——但它紅的
理由跟 ConnectInfo 無關,今天不修,留給 memory 契約裁定之後(修好它會立刻點名
memory.rs 那三條,沒有裁定就讓它紅,不 allowlist)。

修法:沒有地址,就當你是遠端

改一行簽名、加一個 match:

peer: Option<axum::extract::ConnectInfo<std::net::SocketAddr>>,
// ...
let exempt = match peer {
    Some(axum::extract::ConnectInfo(peer)) =>
        crate::auth_gate::caller_is_exempt_local_ui(&state.cluster_manager, peer, req.headers()),
    None => false,   // 不知道你從哪來 → 不給本機豁免 → 必須簽章
};

fail-closed:沒有 peer address 的請求被當成遠端,得簽章。它不再 500,它 401/403。
兩條原本紅的測試不用改一個字——它們本來就在斷言正確的事,只是被 500 騙了。

同一個 commit 補一條放行側的測試,形狀是 Day 10 那道閘要求的:一條 Day 10 遷移過的
caller(get_provider_healthGET /api/providers/health),三個請求——

  1. 沒簽章的遠端呼叫者 → 401/403(這一列有走到閘)
  2. 簽對的呼叫者 → assert_eq!(200) 而且 body 的 providers 是陣列(門開了,
    而且是對的 handler 在回答)
  3. 錯的密鑰簽 → 401(那個 200 是簽章換來的,不是某個豁免)

第三個是紅證。少了它,前兩個一起綠也證明不了門在看簽章。

修之後:先跑那八個 binary

commit 414db8c4。不先跑全量——全量要重 link 201 支 binary、再付 80 分鐘 Gatekeeper;
先只建修之前紅的那 8 個 binary(加新測試那個),57 秒編完、4 分鐘 Gatekeeper:

Starting 2811 tests across 8 binaries (53 tests skipped)
Summary [ 82.956s ] 2811 tests run: 2795 passed, 16 failed, 53 skipped

同一批 binary,修之前 45 紅,修之後 16。兩條新的放行側測試都過:簽對 → 200 而且 body
是對的形狀;沒有地址 → 401/403,不是 500

剩下的 16 條,每一條都讀了訊息:

什麼 今晚怎麼處理
11 skill_rpc_skills 的疑似雙重驗章(上面那段) 修之前就是這個原因,這個 fix 本來就碰不到它;明天紅證再修
2 lib squad_dispatch_testsevents_upload_rejects_too_many_parts_with_413durable_status_survives_restart fail-closed 揭露的:它們模擬本機呼叫者,不簽章、期待 handler 的回答,卻從沒說過自己從哪來;以前 500、現在 401。修法是測試補一個 loopback 地址,兩行——但每改一次 lib-test 就重 link、重付 Gatekeeper,今晚不改
1 p9_the_shell_cannot_pin_itself:/sw.js 的內容 跟 auth 無關,Day 9 的測試,今晚沒動
1 route ratchet 的下限 另案(等 memory 裁定)
1 search_fts5_p99_latency 機器,不是程式

所以「修之後」誠實的數字不是 0,是 16,而且五種。ConnectInfo 那 31 條是真的清掉了——
它們是這個 commit 唯一宣稱的事。

修之後:全量

(待填:full22-after.log —— START/HEAD、Summary、EXIT、END;junit.xml 有沒有留下來)

第三盞:一道從來沒說過「不」的閘

Day 10 寫了 scripts/paired_gate_check.sh:改到閘的 PR,測試裡必須找得到放行側的斷言。
我還對它做了紅證,抓到它只看 + 行、看不到刪掉閘的 PR。我以為它是真的。

今天對整條分支跑它,從 origin/main 到 HEAD,259 個 commit:

paired-gate: ✅ 找到放行側斷言 ——
  b/core/tests/one_signing_scheme.rs:          `rpc_wire::sign_headers` (or `cli_config::signed_peer_request`, which \

它引用的「放行側斷言」,是一條 assert 訊息字串的續行。一段散文。

再看它接受的形狀:assert_ne!(status, 401)。而第二盞燈剛剛才教過——500 也滿足
!= 401
。這道閘的放行側,正好接受會被 500 騙的那種斷言。它從出生到現在,對真實的
diff 沒有說過一次「不」。

改嚴:先把字串字面值剝掉再比對;放行側要同時有「簽章請求的呼叫」跟「正向的狀態
斷言」(assert_eq!(…StatusCode::OK).is_success());assert_ne!(401) 不再算。
然後用五個合成 commit 做紅證:

情境 舊 script 新 script
碰閘 + 測試只有註解和字串裡的 send_signed( ✅ 放行
碰閘 + signed_request + assert_ne!(401) ✅ 放行
碰閘 + signed_request + assert_eq!(OK)
require_cluster_auth 那行刪掉,沒測試
前端 authorize() + expect(200),沒簽章形狀

前兩列是重點:舊的放、新的擋。第三列證明新的不是把所有東西都擋掉。

順帶抓到一件更難堪的:WORKFLOW.md §1 的範例,教人寫的就是 assert_ne!(UNAUTHORIZED)
文件教的斷言形狀,正是會被 500 騙的那種。 改了。

還有一件早上就知道、現在寫進文件的:這道閘沒有接進任何 workflowWORKFLOW.md
第 64 行說「CI 用 scripts/paired_gate_check.sh 檢查這件事」,而 .github/workflows/
底下沒有一個檔案提到它。一個腳本在 repo 裡,跟一道閘在 CI 裡,是兩件事。文件改成
實話:腳本在,還沒接。

第四、五、六盞:三個從來沒亮過的安全燈

GitHub 上 cargo-audit-nightly 每晚跑,gh run list 看過去一排紅。早上的調查員往回翻:

  • 110/110。 從 2026-05-16 加進來的第一次執行起,沒有一次綠。
  • 其中 37 次根本沒啟動——GitHub 回「recent account payments have failed or your
    spending limit needs to be increased」。
  • 其餘每一次都死在同一行:gh issue create --label "security,cargo-audit"
    這個 repo 沒有這兩個 label。所以它每晚都找到 advisory、每晚都試著開 issue、
    每晚都在開 issue 那一步失敗。它寫出來的 audit JSON 也從沒上傳。

一個告警系統,從出生那天起就沒有送出過任何一則告警。而它每晚都「跑了」。

而它每晚找到的 advisory 是什麼?它的 core 那步沒帶 --ignore RUSTSEC-2023-0071,
core/Cargo.lock:4156 就有 rsa 0.9.10——workflow 自己的註解說「rsa 只在
app/src-tauri」,是錯的。它每晚都被一條已知、有文件、不可修的 advisory 絆倒。

修法在 PR #370:core 也 ignore(理由跟 security.yml 同一段)、JSON 上傳成
artifact、告警步驟改成「有開著的 issue 就留言,沒有才開」、label 建起來、最後一步
明確 fail 並說為什麼。

接著開 PR 的時候,兩個 PR 幾秒內又紅了兩個 check。幾秒內紅的通常不是程式,是 check
本身。往回數最近 40 次 pull_request 的 Security Scan:

  • Secret Scanning (gitleaks):40/40 紅。 Resource not accessible by integration——
    在 PR 上這個 action 要透過 API 讀 PR 的 commits,而 job 只給了 contents: read
    它從來沒掃過任何一個 PR。
  • Dependency Review:40/40 紅。 「此 repo 不支援,需要 Dependency graph 與 GitHub
    Advanced Security」。私有 repo 沒有 GHAS,這個 action 在這裡跑不起來

兩個都是 04-23 加的。從那之後每一個 PR 上都掛著兩個紅叉,而每一個 PR 都合併了。
紅叉掛久了,就變成背景。

修法一樣進 #370:gitleaks 補 pull-requests: read、關掉需要 write 的評論;
Dependency Review 在私有 repo 明講跳過,開了 GHAS 再拿掉那個條件。一個跑不了的
check 不是 check
,留著它只是讓「紅」失去意義。

第七盞:main 的 clippy 紅了,沒人看見

PR #369 只改兩個 Cargo.lock,結果 CI Fast 紅在 clippy:

error: using `chunks_exact` with a constant chunk size
   --> src/embeddings/mod.rs:110:24
error: using `chunks_exact` with a constant chunk size
   --> src/skill_wire.rs:2331:24

程式碼沒動。動的是 dtolnay/rust-toolchain@stable——它不釘版本,stable 走到 1.98,
帶來新的 lint chunks_exact_to_as_chunksorigin/main 08-12 之後沒有任何 push 或
PR,而 main 上的 workflow 只在 push/PR 時跑,所以它紅的那一天,沒有任何東西跑起來
讓人看見它紅了

寫到這裡我以為故事是「main 本來綠的,工具鏈前進讓它紅了」。去翻 08-12 那次——
main 最後一次有人推它——的 CI Fast:那時就已經紅了,兩個 job 都紅,紅在下一節
那條測試。clippy 不是 main 變紅的原因,是疊上去的最新一層。main 從最後一次有人推它
那天起就是紅的,只是紅的理由換過。

兩處是同一個模式(decode little-endian f32 blob),改成 as_chunks::<4>()(1.88
起穩定),不用 #[allow] 蓋。PR #371,而且要先合它——不然 #369、#370 對 main 的
CI Fast 永遠紅。

這盞燈的教訓跟前面不一樣:它不是壞的。它是對的、而且沒有人看。一盞正確的燈在
沒有人看的地方變紅,跟一盞壞掉的燈,結果一樣。

第八盞:剝掉一層紅,下面還有一層

從外面看是一個紅叉;剝開是 clippy,再剝開是壞掉一個月的 Linux 安裝路徑

PR #371 把 clippy 修掉,同一個 job 接著跑 cargo test --lib,在 ubuntu runner 上:

test service::linux::tests::systemd_unit_file_content_correct ... FAILED
    ExecStart not substituted with bin path:
    [Unit]
    Description=Phantom Mesh agent daemon (per-user)
    ...
test result: FAILED. 2632 passed; 1 failed; 52 ignored

08-06 的改名把程式碼裡的替換目標改成 __SPECTYN_BIN__,而 templates/ 底下四個模板
還是 __PHANTOM_BIN__。所以 main 上的 spectyn service install,從改名那天起寫出來
的 unit file 就沒有 ExecStart
——Linux 的安裝路徑壞了一個月。

這件事 dev 分支在 08-28 就修了(「四個模板滯留 phantom 佔位,install 全斷」),
從沒回流 main。而唯一會叫的那條測試,住在 #[cfg(target_os = "linux")] 的模組裡——
Mac 上跑多少次全量都碰不到它;它唯一活著的地方是 main 的 CI Fast,而那個 job 紅在
clippy 的那層上面,沒有人往下翻。

一盞燈蓋住另一盞燈。 第一盞紅得無關緊要(lint),第二盞紅得要命(安裝壞了),
從外面看是同一個紅叉。修法搬進 #371:四個模板、環境變數清單補 SPECTYN_PORT,
還有那條「模板不准再帶 phantom 時代名字」的 ratchet——讓 main 上也有一盞會為這件事
變紅的燈。

搬完,「Check + Clippy + Unit Tests」在 ubuntu 上綠了——這個 job 從 08-06 改名以來
第一次。然後同一個 run 的 Cargo Tests 露出第三層:

selfupdate_verify_tests::good_sha_passes
  left:  d01203a2…   ← sha256("spectyn")
  right: 3bb68de6…   ← sha256("phantom")

改名把測試的 payload 從 "phantom" 改成 "spectyn",旁邊那個「已知正確的摘要」
沒跟著改。同一次改名、同一種債,第二筆。這條測試在 main 上從改名那天起一次都沒被
執行過
:cargo test 跑到 lib 的 systemd 測試就停了,bin 的測試永遠排不到——
所以它甚至不是「紅了沒人看」,它是從來沒有機會紅

三層,一個紅叉。剝的過程本身就是量測:每剝一層,才知道下面還有沒有。

修掉第三層,Cargo Tests 露出第四層:

search_fts5_p99_latency_under_200ms_with_1000_rows
  FTS5 search p99 must stay <200ms over a ~1000-row bank, got p99=201ms

201 對 200。這一層跟前三層不同類:它不是程式錯,是一條時間斷言在 GitHub 的共用
runner 上量到了機器
。dev 分支的 nextest.toml 早就把這類測試隔離成序列組、給一次
重試,理由寫在檔案頂端——「量到的是十五個行程搶同一顆核心,不是程式碼」。main 上沒有
這份設定,所以它是 main 上第一盞紅得對、但不是 bug 的燈。

我在這裡停。三層是改名債和工具鏈漂移,今天修得完;第四層要把那份隔離設定搬去
main,是另一張卡。Integration Tests 也紅著,今天沒看——寫在這裡,不寫成看過了。

第九盞:Security Scan 紅在真的 advisory

三盞「紅得對」的燈裡最單純的一盞——也是一樣沒人讀。08-24 起 Security Scan 紅在 h2 0.4.14,
RUSTSEC-2026-0258(unbounded empty DATA frames,DoS,low)。08-17 那次綠,是因為
advisory 是 08-17 那天才進資料庫。

修法是兩個 lockfile 各一行:cargo update -p h2 → 0.4.19。PR #369。

順帶量到一件小事:cargo update -p h2 在 core 的 lock 裡不只動 h2,還重排了
windows-sys / socket2 的統一、刪了 10 條不可達的 windows-* 0.53.x。我先懷疑是 lock
跟 Cargo.toml 漂移,用 cargo metadata --locked 量——改前改後都 rc=0,沒漂移,是
cargo 重解的連鎖。懷疑要用量的殺,不是用猜的。

我在 Day 10 寫錯了四句

Day 10 有一節「我在昨天的文章裡寫錯一句」。今天升級成四句:

  1. 「那兩條測試會紅」——那兩條不紅。紅的是 ConnectInfo 家族,而且是上一輪全量
    已經跑出來、我沒看的兩條。(數字見第二盞)
  2. 「沒人跑的第二 daemon」——它在 tauri.conf.jsonexternalBin 裡,
    copy-sidecar.sh 缺它會 fail,本機 Spectyn Mesh.app 裡有一支 18 MB 的它,
    daemon.rs::start_daemon 可以從對話畫面把它拉起來。
    the_other_daemon_does_not_ship.rs 只看三個 shell script 就宣稱「沒有東西出貨它」——
    「清點器只清點它名字裡那片」,第五次。
  3. 「留成 404,由 CI 每次指名它」——那條 ratchet 的掃描器跳過所有 "{}/..."
    形式的字面值,checked=0,它會先撞自己的下限斷言,永遠不會點名 memory.rs。
  4. 五張圖把還沒裁定、還沒完成的事畫成綠色——成對測試圖把沒做的 positive test
    畫成 ADMIT ✓、官方限制圖把待裁決的商店架構畫成綠色 SLA、三開口圖少一條 NO ROUTE、
    Ratchet/近中遠/120 天三張把未來目標畫綠。發表前審查就抓到了,我照樣發了。

第四句最難堪,因為它不是判斷錯誤。是知道錯了還按下發表——文字勘誤放明天,圖先
將就。這一篇的圖,沒裁定的事一律虛線。

這一天學到的

一、「跑了」跟「亮了」是兩件事。 nightly 每晚都跑,從沒送出過告警。gitleaks 每個
PR 都跑,從沒掃過一個 PR。paired gate 對 259 個 commit 都跑了,從沒說過不。跑了只
證明程序存在。

二、正確的燈在沒人看的地方,等於壞的燈。 main 的 clippy 紅得對;vitest 綠得對。
兩盞都一週沒人看。專案得到的資訊是一樣的:零。燈的價值不在它對不對,在它紅的時候
有沒有人會看到
——而 dev 分支上零次 workflow 觸發,意思是這條分支上的燈全部沒人看。

拒絕 401、放行 200、壞掉 500:assert_ne!(401) 對後兩者都是綠的

三、500 是第三種顏色。 拒絕是 401,放行是 200,而 500 兩邊都不是——它會讓
assert_ne!(401) 綠、讓「該拒的被拒了」成立、讓一道閘以為自己在工作。今天三盞燈
(全量、paired gate、WORKFLOW.md 的範例)壞的方式都是同一個:把「不是 401」讀成
「放行了」。

接下來

  • 綠燈紀錄還沒有。 修之後的全量在寫這一段的時候還在跑(20:13 起跑,201 支 binary
    重 link,Gatekeeper 估 80 分鐘)。它的 Summary 行、EXIT 跟 commit hash 會補在上面
    「修之後:全量」那一節——補上之前,這篇不能說今天有綠燈紀錄。而且按 targeted 的數字,
    它不會是 0 紅,會是 16 上下:11 條疑似雙重驗章、2 條沒說自己從哪來的本機測試、
    1 條 sw.js、1 條 ratchet、1 條 latency。明天的第一件事就是這 16 條,一種一種來,
    每一種先紅證。
  • Gatekeeper 是一盞要關掉的燈。 今天兩次全量、一次 targeted,加起來超過兩小時在
    syspolicyd。Terminal 進「開發者工具」豁免是操作者才能按的那一下。
  • 三個 PR 的合併順序:#371(clippy)→ 重跑 #369、#370。都只存 PR,合併是 owner
    的事。合併後 workflow_dispatch 跑一次 nightly,看 artifact 跟 issue 有沒有出現。
  • dev 分支要有燈:ci-fastdev/** trigger——但要在全量綠了之後,否則每次
    push 都紅。paired gate 改嚴之後才接進去。
  • 交付還沒發生:操作者在跑的 binary 是 08-28 建的,早於全部 Day 9/10 的 auth 修正。
    綠燈之後 → install.sh → service 重裝,順序不能反。
  • 兩個要裁定的:memory 三條(刪 / 接 /rpc/recall 誠實改名 / 蓋後端)、
    第二 daemon(直接刪 / 先併再刪)。「留著加閘」違反 08-06「只有一個後端」的裁定。

執行紀錄(2026-09-04)

時間 證據
上午 22 agent 唯讀對抗式調查(7 調查員 / 14 駁斥者 / 1 批評者),不跑 cargo 721 次工具呼叫,0 錯誤
18:17 全量「修之前」起跑,主 tree,--no-fail-fast HEAD b7377c13,core 乾淨
18:18 app vitest 全套 118 檔 / 653 passed / 8 skipped / 0 failed / 19 s
18:19 三個 commit 收掉 25 個未提交檔 8e867e3e e4eaee3e 08054359
18:20 量 origin/main 的 lockfile 有沒有漂移 cargo metadata --locked rc=0,改前改後都是
18:24 PR #369(h2 → 0.4.19)、PR #370(nightly) label security cargo-audit 建了
18:25 兩個 PR 幾秒內紅三個 check Dependency Review / gitleaks / SPEC-01 Serves:
18:28 PR #369 紅在 clippy → main 本身紅 chunks_exact_to_as_chunks ×2,stable 1.98
18:31 paired gate 改嚴 + 五個合成 commit 紅證 c5948d9f
18:32 PR #371(clippy) db0dced6
18:34 PR #370 併入 gitleaks 權限 + Dependency Review 跳過 40/40 + 40/40,回溯到 06-10
18:36 全量編譯完成(18m35s),進 Gatekeeper syspolicyd 40% CPU,~55 分鐘
19:20 PR #371 clippy 過,cargo test --lib 露出第二層 2632 passed / 1 failed,__PHANTOM_BIN__
19:26 模板修正搬進 #371 83b41db6(從 dev 的 1e529998 搬四個模板 + ratchet)
19:35 #371 的 Unit Tests (改名以來第一次);Cargo Tests 露出第三層 GOOD_SHA = sha256("phantom") → c1ae414c
19:37 翻 main 08-12 的最後一次 CI Fast:當時就紅 run 31588217398,兩個 job 都紅在 systemd
19:54 第四層:latency 斷言在共用 runner 上 201 ms vs 200 停在第三層,另開卡
20:02 全量「修之前」結束 3591 run / 3546 passed / 45 failed / 70 skipped;編譯 18m35s + Gatekeeper ~81 min + 實跑 176 s
20:04 ConnectInfo fail-closed + positive test + nextest slow-timeout/junit 414db8c4
20:10 targeted(8 binary):45 → 16 紅;兩條 positive test 過 2811 run / 2795 passed / 16 failed / 82.9 s
20:13 全量「修之後」起跑 HEAD 414db8c4,core 乾淨
(待填) 全量「修之後」結果

上一篇
Day 10:門關上了,呼叫端還連得到嗎?
下一篇
Day 12(上):先證明它會紅
系列文
從單一agent 到多agent 集群的開發流水帳以及應用18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言